package com.muyu.api.handler;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.muyu.api.annotation.NoWrapResponse;
import com.muyu.api.entity.ResponseEntity;
import com.muyu.api.enums.ApiStatusEnum;
import com.muyu.api.exception.BusinessException;
import com.muyu.api.response.ResultResponse;
import com.muyu.api.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.stream.Collectors;

/**
 * @ClassName: GlobalResponseHandler
 * @Author: Zirun.Xin
 * @Date: 2025/4/9 下午3:30
 * @Version: 1.0
 * @Description: 全局响应处理组件（统一API契约）
 */
@Slf4j
@RestControllerAdvice(basePackages = "com.muyu.controller")
public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 排除以下情况：
        // 1. 方法已标记@NoWrapResponse注解
        // 2. 返回类型本身就是ResultResponse
        // 3. 返回类型是文件下载等特殊类型
        return ! returnType.hasParameterAnnotation(NoWrapResponse.class) &&
                ! returnType.getParameterType().isAssignableFrom(ResultResponse.class) &&
                ! returnType.getParameterType().isAssignableFrom(ResponseEntity.class);
    }

    /**
     * 响应数据包装处理
     * @param body 原始响应体
     * @param returnType 方法返回类型
     * @param mediaType 媒体类型
     * @param converterType 消息转换器
     * @param request 当前请求
     * @param response 响应对象
     * @return 包装后的响应体
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                  MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> converterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {

        // 处理void返回类型
        if (body == null && returnType.getParameterType().equals(void.class)) {
            return ResultResponse.ok(null);
        }

        // 字符串类型特殊处理（避免String转换异常）
        if (body instanceof String) {
            return JsonUtils.toJson(ResultResponse.ok(body));
        }

        // 其他类型统一包装
        return ResultResponse.ok(body);
    }

    /*------------ 全局异常处理 ------------*/

    /**
     * 处理业务自定义异常
     * @param ex 业务异常
     * @return 错误响应
     */
    @ExceptionHandler(BusinessException.class)
    public ResultResponse<Void> handleBusinessException(BusinessException ex) {
        return ResultResponse.fail(ex.getCode(), ex.getMessage());
    }

    /**
     * 处理参数校验异常（JSR303规范）
     * @param ex 校验异常
     * @return 错误响应
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultResponse<Void> handleValidationException(MethodArgumentNotValidException ex) {
        String errorMsg = ex.getBindingResult().getFieldErrors()
                .stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining("; "));
        return ResultResponse.fail(ApiStatusEnum.BAD_REQUEST.getCode(), errorMsg);
    }

    /**
     * 处理绑定异常（表单提交等场景）
     * @param ex 绑定异常
     * @return 错误响应
     */
    @ExceptionHandler(BindException.class)
    public ResultResponse<Void> handleBindException(BindException ex) {
        String errorMsg = ex.getBindingResult().getFieldErrors()
                .stream()
                .map(f -> f.getField() + ": " + f.getDefaultMessage())
                .collect(Collectors.joining("; "));
        return ResultResponse.fail(ApiStatusEnum.BAD_REQUEST.getCode(), errorMsg);
    }

    /**
     * 处理JSON操作异常（JSON转换）
     * @param ex JSON操作异常
     * @return 错误响应
     */
    @ExceptionHandler(JsonProcessingException.class)
    public ResultResponse<Void> handleJsonException(JsonProcessingException ex) {
        return ResultResponse.fail(ApiStatusEnum.INTERNAL_ERROR.getCode(), "JSON处理失败：" + ex.getMessage());
    }

    /**
     * 处理未捕获的全局异常（兜底处理）
     * @param ex 异常对象
     * @return 标准错误响应
     */
    @ExceptionHandler(Exception.class)
    public ResultResponse<Void> handleGlobalException(Exception ex) {
        // 记录完整的错误堆栈
        log.error("Global exception caught: {}", ex.getMessage(), ex);
        return ResultResponse.fail(ApiStatusEnum.INTERNAL_ERROR.getCode(),
                "系统繁忙，请稍后再试");
    }
}
